What is JVM? Explain JVM Architecture

โšก Smart Summary

Java Virtual Machine (JVM) is the engine that provides a runtime environment to drive Java code, converting platform-independent bytecode into native machine language. It forms part of the Java Runtime Environment and enables Java’s write-once, run-anywhere portability.

  • ๐Ÿงฉ Bytecode Bridge: The Java compiler produces bytecode instead of machine code, and the JVM interprets that bytecode on any host system.
  • ๐Ÿ—๏ธ Core Architecture: JVM combines a ClassLoader, method area, heap, stacks, PC registers, and an execution engine to run programs.
  • ๐Ÿ”„ Compilation Flow: Unlike C, Java requires no linking; class files are loaded into RAM, verified, and then executed at runtime.
  • โšก JIT Compiler: The Just-In-Time compiler converts bytecode into native machine code during execution to improve performance.
  • ๐Ÿข Performance Note: Dynamic linking and runtime interpretation historically make Java slower, though modern versions largely close that gap.

JVM Architecture

What is JVM in Java?

Java Virtual Machine (JVM) is an engine that provides a runtime environment to drive the Java code or applications. It converts Java bytecode into machine language. JVM is a part of the Java Runtime Environment (JRE). In other programming languages, the compiler produces machine code for a particular system. However, the Java compiler produces code for a Virtual Machine known as the Java Virtual Machine.

How JVM Works?

First, Java code is compiled into bytecode. This bytecode gets interpreted on different machines. Between the host system and the Java source, bytecode is an intermediary language. JVM in Java is responsible for allocating memory space.

Working of Java Virtual Machine JVM

Working of Java Virtual Machine (JVM)

Architecture of JVM (Java Virtual Machine)

Now, let us understand the architecture of JVM. JVM architecture in Java contains a classloader, memory area, execution engine, and more.

JVM Architecture

Java Virtual Machine Architecture

1) ClassLoader
The class loader is a subsystem used for loading class files. It performs three major functions, namely Loading, Linking, and Initialization.

2) Method Area
The JVM Method Area stores class structures like metadata, the constant runtime pool, and the code for methods.

3) Heap
All the Objects, their related instance variables, and arrays are stored in the heap. This memory is common and shared across multiple threads.

4) JVM Language Stacks
Java language stacks store local variables and their partial results. Each thread has its own JVM stack, created simultaneously as the thread is created. A new frame is created whenever a method is invoked, and it is deleted when the method invocation process is complete.

5) PC Registers
The PC register stores the address of the Java virtual machine instruction that is currently executing. In Java, each thread has its own separate PC register.

6) Native Method Stacks
Native method stacks hold the instructions of native code that depend on the native library. It is written in another language instead of Java.

7) Execution Engine
The execution engine reads the bytecode and executes it piece by piece. It uses an interpreter and a Just-In-Time (JIT) compiler to convert bytecode into native machine code and run it.

8) Native Method Interface
The Native Method Interface is a programming framework. It allows Java code running in a JVM to call, and be called by, native applications and libraries.

9) Native Method Libraries
Native Libraries is a collection of the native libraries (C, C++) which are needed by the Execution Engine.

Software Code Compilation & Execution process

In order to write and execute a software program, you need the following:

  • 1) Editor โ€“ To type your program into; a notepad could be used for this.
  • 2) Compiler โ€“ To convert your high-level language program into native machine code.
  • 3) Linker โ€“ To combine the different program file references in your main program together.
  • 4) Loader โ€“ To load the files from your secondary storage device like a Hard Disk, Flash Drive, or CD into RAM for execution. The loading is automatically done when you execute your code.
  • 5) Execution โ€“ Actual execution of the code, which is handled by your OS and processor.

With this background, refer to the following video and learn the JVM internal working and architecture of JVM (Java Virtual Machine).

Click here if the video is not accessible

C code Compilation and Execution process

To understand the Java compiling process, let us first take a quick look at the compiling and linking process in C.

Suppose in the main function you have called two functions, f1 and f2. The main function is stored in the file a1.c.

C code main function a1.c

Function f1 is stored in a file a2.c.

C code function f1 a2.c

Function f2 is stored in a file a3.c.

C code function f2 a3.c

All these files, i.e., a1.c, a2.c, and a3.c, are fed to the compiler, whose output is the corresponding object files, which are the machine code.

C code compiler produces object files

The next step is integrating all these object files into a single .exe file with the help of a linker. The linker will club all these files together and produce the .exe file.

C code linker produces exe file

During the program run, a loader program will load a.exe into the RAM for execution.

C code loader loads exe into RAM

Java code Compilation and Execution in Java VM

Now, let us look at the process for Java. In your main, you have two methods, f1 and f2.

  • The main method is stored in the file a1.java
  • f1 is stored in a file as a2.java
  • f2 is stored in a file as a3.java

Java code compiles three files to class files

The compiler will compile the three files and produce three corresponding .class files, which consist of BYTE code. Unlike C, no linking is done.

The Java VM, or Java Virtual Machine, resides on the RAM. During execution, using the class loader, the class files are brought into the RAM. The BYTE code is verified for any security breaches.

Java class loader brings class files into RAM

Next, the execution engine will convert the bytecode into native machine code. This is just-in-time compiling. It is one of the main reasons why Java is comparatively slow.

Java execution engine converts bytecode to native code

NOTE: JIT, or the Just-in-time compiler, is the part of the Java Virtual Machine (JVM). It interprets parts of the byte code that have similar functionality at the same time.

Why is Java both Interpreted and Compiled Language?

Programming languages are classified as:

  • Higher-Level Language, e.g., C++, Java
  • Middle-Level Languages, e.g., C
  • Low-Level Language, e.g., Assembly
  • Finally, the lowest level as the Machine Language

A compiler is a program that converts a program from one level of language to another. For example, the conversion of a C++ program into machine code. The Java compiler converts high-level Java code into bytecode (which is also a type of machine code).

An interpreter is a program that converts a program at one level to another programming language at the same level. For example, the conversion of a Java program into C++.

In Java, the Just-In-Time code generator converts the bytecode into the native machine code, which are at the same programming levels. Hence, Java is both a compiled as well as an interpreted language.

Why is Java slow?

The two main reasons behind the slowness of Java are:

  1. Dynamic Linking: Unlike C, linking is done at run-time, every time the program is run in Java.
  2. Run-time Interpreter: The conversion of byte code into native machine code is done at run-time in Java, which further slows down the speed.

However, the latest versions of Java have addressed these performance bottlenecks to a great extent.

FAQs

The JVM runs AI and big-data frameworks such as Deeplearning4j, Weka, and Apache Spark. Its Just-In-Time compiler and memory management let these libraries process large datasets efficiently across platforms without rewriting native code.

Yes. AI-assisted profilers can analyse garbage collection logs, suggest heap sizes, and flag slow methods. They help tune JVM flags and spot bottlenecks faster, though a developer should still validate every recommended change.

The JVM runs bytecode. The JRE bundles the JVM with core libraries needed to run Java programs. The JDK adds development tools such as the compiler and debugger, so it is used to build applications.

Bytecode is platform independent, but the JVM itself is platform dependent. Each operating system needs its own JVM implementation. This design lets the same compiled bytecode run anywhere a compatible JVM is installed.

Summarize this post with: